﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlTypes;

namespace Grinko.HardAndSoftNull
{
    /// <summary>
    /// Discribing soft null
    /// </summary>
    public class Person : INullable, IAssignable
    {

        #region Constructors

        /// <summary>
        /// Empty constructor
        /// </summary>
        public Person()
            : this(0, string.Empty, string.Empty, DateTime.Now)
        {
        }

        /// <summary>
        /// Full constructor for person
        /// </summary>
        /// <param name="code">Person's code</param>
        /// <param name="firstname">Person's firstname</param>
        /// <param name="lastname">Person's lastname</param>
        /// <param name="bdate">Person's birthday</param>
        public Person(int code, string firstname, string lastname, DateTime bdate)
        {
            this.Code = code;
            this.FirstName = firstname;
            this.LastName = lastname;
            this.BDate = bdate;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Person Code
        /// </summary>
        public int Code
        {
            get { return m_Code; }
            set
            {
                if (!IsNull)
                    m_Code = value;
            }
        }

        /// <summary>
        /// Person FirstName
        /// </summary>
        public string FirstName
        {
            get { return m_FirstName; }
            set
            {
                if (!IsNull)
                    m_FirstName = value;
            }
        }

        /// <summary>
        /// Person LastName
        /// </summary>
        public string LastName
        {
            get { return m_LastName; }
            set
            {
                if (!IsNull)
                    m_LastName = value;
            }
        }

        /// <summary>
        /// Person Birthday
        /// </summary>
        public DateTime BDate
        {
            get { return m_BDate; }
            set
            {
                if (!IsNull)
                    m_BDate = value;
            }
        }

        #endregion Properties

        #region INullable implementation

        public bool IsNull
        {
            get { return m_Null; }
        }

        public static Person Null { get { return new Person() { m_Null = true }; } }

        #endregion

        #region IAssignable Implementation

        /// <summary>
        /// Content transfer
        /// </summary>
        /// <param name="obj">Object that takes content</param>
        /// <exception cref="ArgumentNullException">If object, that takes content is a null object </exception>
        /// <exception cref="NotSupportedException">If object, that takes content isn't supported by method</exception>
        /// <exception cref="InvalidOperationException">If current object is nullable</exception>
        public void AssignTo(object obj)
        {
            if (IsNull)
                throw new InvalidOperationException("Object is nullable!");

            if (obj == null)
                throw new ArgumentNullException("Content is a null!");

            if (obj is Person)
            {
                Person item = obj as Person;
                item.m_Null = false;
                item.Code = this.Code;
                item.BDate = this.BDate;
                item.FirstName = this.FirstName;
                item.LastName = this.LastName;
            }

            throw new NotSupportedException();
        }

        #endregion

        #region Private Fields

        private bool m_Null = false;
        private int m_Code = default(int);
        private string m_FirstName = default(string);
        private string m_LastName = default(string);
        private DateTime m_BDate = default(DateTime);

        #endregion
    }
}
